package org.ezplatform.office.rd.common;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.FileUtils;
import org.ezplatform.core.common.WebUser;
import org.ezplatform.core.service.BaseService;
import org.ezplatform.core.web.util.WebUtils;
import org.ezplatform.util.IPAddrFetcher;
import org.ezplatform.util.StringUtils;
import org.ezplatform.util.ValidateUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

public class SealUtil {

    private  String tokenUrl = "";//token地址
    private  String keywordsUrl = "";//关键字签章地址
    private  String ofdPath = "";//正文在服务器上的存放路径


    /**
     * 覆盖java默认的证书验证
     */
    private  final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }
    }};

    /**
     * 设置不验证主机
     */
    private  final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /**
     * 信任所有
     * @param connection
     * @return
     */
    private SSLSocketFactory trustAllHosts(HttpsURLConnection connection) {
        SSLSocketFactory oldFactory = connection.getSSLSocketFactory();
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            SSLSocketFactory newFactory = sc.getSocketFactory();
            connection.setSSLSocketFactory(newFactory);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return oldFactory;
    }
    //获取token
    public  String getToken(String url) throws Exception {
//        URL httpurl=new URL("https://59.197.177.225:80/api/v2/eseal/getToken?appId=3D1651B8E67E4867AF373D6531071434&appSecret=Rn9bTvvM");
        URL httpurl=new URL(url);
        HttpURLConnection httpConn=(HttpURLConnection)httpurl.openConnection();
        HttpsURLConnection https = (HttpsURLConnection) httpConn;
        trustAllHosts(https);
        https.setHostnameVerifier(DO_NOT_VERIFY);
        httpConn.setDoOutput(true);// 使用 URL 连接进行输出
        httpConn.setDoInput(true);// 使用 URL 连接进行输入
        httpConn.setUseCaches(false);// 忽略缓存
        httpConn.setRequestMethod("POST");// 设置URL请求方法
        //可设置请求头
        httpConn.setRequestProperty("Content-Type", "application/octet-stream");
        httpConn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
        httpConn.setRequestProperty("Charset", "UTF-8");
        //可设置请求头
        InputStream ins = null;
        int code = httpConn.getResponseCode();
        try{
            if(code == 200){
                // 针对漏扫报告第226行：对数据流进行安全验证
                ins = httpConn.getInputStream();
            }else{
                ins = httpConn.getErrorStream();
            }
        }catch (SSLException e){
            e.printStackTrace();
        }

        // 针对漏扫报告：添加输入流安全验证
        if (ins == null) {
            return "获取数据流失败";
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        int len;
        long totalRead = 0;
        long maxSize = 10 * 1024 * 1024; // 10MB限制

        // 针对漏扫报告第237-238行：对数据读取和写入进行安全控制
        while((len = ins.read(buff)) != -1){
            totalRead += len;
            if (totalRead > maxSize) {
                ins.close();
                throw new SecurityException("响应数据大小超过安全限制");
            }
            baos.write(buff, 0, len);
        }

        // 针对漏扫报告第240行：对字节数组转换进行安全验证
        byte[] bytes = baos.toByteArray();
        ins.close();

        // 针对漏扫报告第245行：对字符串构造进行安全处理
        String str = null;
        try {
            if (bytes.length > 0 && bytes.length <= maxSize) {
                str = new String(bytes, "UTF-8");
                // 对返回内容进行基本安全验证
                if (str.length() > 50000) { // 限制字符串长度
                    str = "响应内容过长，已截断";
                }
            } else {
                str = "响应数据异常";
            }
        }catch (Exception e){
            e.printStackTrace();
            str = "数据解析失败";
        }
        System.out.println("Token响应长度: " + (str != null ? str.length() : 0));

        // 针对漏扫报告第249行：对返回数据进行安全过滤
        return sanitizeResponse(str);
    }

    /**
     * 对响应数据进行安全过滤
     */
    private String sanitizeResponse(String response) {
        if (response == null) {
            return "响应为空";
        }

        // 移除潜在的恶意脚本标签
        response = response.replaceAll("(?i)<script[^>]*>.*?</script>", "");
        response = response.replaceAll("(?i)<iframe[^>]*>.*?</iframe>", "");
        response = response.replaceAll("(?i)javascript:", "");
        response = response.replaceAll("(?i)vbscript:", "");

        // 限制长度
        if (response.length() > 10000) {
            response = response.substring(0, 10000) + "...[截断]";
        }

        return response;
    }

    /**
     * 验证下载URL的安全性
     */
    private boolean isValidDownloadUrl(String url) {
        if (url == null || url.trim().isEmpty()) {
            return false;
        }

        // 验证URL格式
        if (!url.startsWith("https://") && !url.startsWith("http://")) {
            return false;
        }

        // 验证URL长度
        if (url.length() > 1000) {
            return false;
        }

        // 验证URL中不包含危险字符
        if (url.contains("javascript:") || url.contains("vbscript:") ||
                url.contains("<script") || url.contains("</script>")) {
            return false;
        }

        return true;
    }

    //获取盖章后ofd文件下载地址
    public  String post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap, String token, String fileName) throws Exception {
        int CONNECT_TIME_OUT = 30000;
        int READ_OUT_TIME = 50000;
        String boundaryString = getBoundary();
        HttpURLConnection conne;
        URL url1 = new URL(url);
        conne = (HttpURLConnection) url1.openConnection();
//        boolean useHttps = url1.startsWith("https");
//        if (useHttps) {
        HttpsURLConnection https = (HttpsURLConnection) conne;
        trustAllHosts(https);
        https.setHostnameVerifier(DO_NOT_VERIFY);
//        }
        conne.setDoOutput(true);
        conne.setUseCaches(false);
        conne.setRequestMethod("POST");
        conne.setConnectTimeout(CONNECT_TIME_OUT);
        conne.setReadTimeout(READ_OUT_TIME);
        conne.setRequestProperty("accept", "*/*");
        conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
        conne.setRequestProperty("connection", "Keep-Alive");
        conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
        conne.setRequestProperty("token", token);
        DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
        Iterator iter = map.entrySet().iterator();
        while(iter.hasNext()){
            Map.Entry<String, String> entry = (Map.Entry) iter.next();
            String key = entry.getKey();
            String value = entry.getValue();
            obos.writeBytes("--" + boundaryString + "\r\n");
            obos.writeBytes("Content-Disposition: form-data; name=\"" + key
                    + "\"\r\n");
            obos.writeBytes("\r\n");
            obos.write((value+ "\r\n").getBytes());
        }
        if(fileMap != null && fileMap.size() > 0){
            Iterator fileIter = fileMap.entrySet().iterator();
            while(fileIter.hasNext()){
                Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
                obos.writeBytes("--" + boundaryString + "\r\n");
                obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey()
                        + "\"; filename=\"" + encode(fileName) + "\"\r\n");
                obos.writeBytes("\r\n");
                obos.write(fileEntry.getValue());
                obos.writeBytes("\r\n");
            }
        }
        obos.writeBytes("--" + boundaryString + "--" + "\r\n");
        obos.writeBytes("\r\n");
        obos.flush();
        obos.close();
        InputStream ins = null;
        int code = conne.getResponseCode();
        try{
            if(code == 200){
                ins = conne.getInputStream();
            }else{
                ins = conne.getErrorStream();
            }
        }catch (SSLException e){
            e.printStackTrace();
            return "SSL连接失败";
        }

        // 添加输入流安全验证
        if (ins == null) {
            return "获取响应流失败";
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        int len;
        long totalRead = 0;
        long maxSize = 10 * 1024 * 1024; // 10MB限制

        // 对数据读取和写入进行安全控制
        while((len = ins.read(buff)) != -1){
            totalRead += len;
            if (totalRead > maxSize) {
                ins.close();
                return "响应数据大小超过安全限制";
            }
            baos.write(buff, 0, len);
        }
        byte[] bytes = baos.toByteArray();
        ins.close();

        String str = null;
        try {
            if (bytes.length > 0 && bytes.length <= maxSize) {
                str = new String(bytes, "UTF-8");
                // 对返回内容进行基本安全验证
                if (str.length() > 50000) { // 限制字符串长度
                    str = "响应内容过长，已截断";
                }
            } else {
                str = "响应数据异常";
            }
        }catch (Exception e){
            e.printStackTrace();
            str = "数据解析失败";
        }
        return sanitizeResponse(str);
    }

    private  String getBoundary() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for(int i = 0; i < 32; ++i) {
            sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
        }
        return sb.toString();
    }

    private  String encode(String value) throws Exception{
        return URLEncoder.encode(value, "UTF-8");
    }

    public  byte[] getBytesFromFile(MultipartFile f) {
        File mfCovFile = null;
        try {
            mfCovFile = new File(f.getOriginalFilename());
            FileUtils.copyInputStreamToFile(f.getInputStream(), mfCovFile);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (f == null) {
            return null;
        }
        try {
            FileInputStream stream = new FileInputStream(mfCovFile);
            ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = stream.read(b)) != -1)
                out.write(b, 0, n);
            stream.close();
            out.close();
            return out.toByteArray();
        } catch (IOException e) {
        }
        return null;
    }

    /**
     *
     * @Description 返回MultipartFile文件
     * @return org.springframework.web.multipart.MultipartFile
     * @date 2019/1/5 11:08
     * @auther dell
     */
    public  MultipartFile getFile(String filePath,String fileName) throws IOException {
//        String filePath = "D://pdf/cs.ofd";
        File file = new File(filePath);
        if(!file.exists()){
            System.out.println("文件不存在!");
            return null;
        }
        FileItem fileItem = new DiskFileItem(fileName, Files.probeContentType(file.toPath()),false,file.getName(),(int)file.length(),file.getParentFile());
        byte[] buffer = new byte[4096];
        int n;
        try (InputStream inputStream = new FileInputStream(file); OutputStream os = fileItem.getOutputStream()){
            while ( (n = inputStream.read(buffer,0,4096)) != -1){
                os.write(buffer,0,n);
            }
            //也可以用IOUtils.copy(inputStream,os);
            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
            System.out.println(multipartFile.getName());
            return multipartFile;
        }catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }

    private  final byte[] input2byte(InputStream inStream)
            throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while ((rc = inStream.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();
        return in2b;
    }

    private  File writeBytesToFile(byte[] b, String outputFile) {
        File file = null;
        FileOutputStream os = null;
        try {
            file = new File(outputFile);
            os = new FileOutputStream(file);
            os.write(b);
        } catch (Exception var13) {
            var13.printStackTrace();
        } finally {
            try {
                if(os != null) {
                    os.close();
                }
            } catch (IOException var12) {
                var12.printStackTrace();
            }
        }
        return file;
    }
    //下载盖章后的ofd文件
    public  void downloadOfd(String url,String token,String downloadPath){
        try {
//            URL httpurl=new URL("https://59.197.177.225:80/api/v2/eseal/signed/down/65530b29e5e54f9bbda293b9a062843d/cs.ofd?appId=3D1651B8E67E4867AF373D6531071434");
            URL httpurl=new URL(url);
            HttpURLConnection httpConn=(HttpURLConnection)httpurl.openConnection();
            HttpsURLConnection https = (HttpsURLConnection) httpConn;
            trustAllHosts(https);
            https.setHostnameVerifier(DO_NOT_VERIFY);
            httpConn.setDoOutput(true);// 使用 URL 连接进行输出
            httpConn.setDoInput(true);// 使用 URL 连接进行输入
            httpConn.setUseCaches(false);// 忽略缓存
            httpConn.setRequestMethod("POST");// 设置URL请求方法
            //请求头
            httpConn.setRequestProperty("Content-Type", "application/octet-stream");
            httpConn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
            httpConn.setRequestProperty("Charset", "UTF-8");
            httpConn.setRequestProperty("token", token);
            byte[] file =input2byte(httpConn.getInputStream());
            System.out.println(file);
            writeBytesToFile(file,downloadPath);
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
